﻿// <copyright file="BetterAzureTableStorageTests.cs" company="N/A">
//     Copyright (c) Nicholas Barrett and Benjamin Kasten.  All rights reserved.
//
//     This program is free software; you can redistribute it and/or modify it
//     under the terms of the GNU General Public License as published by the
//     Free Software Foundation; either version 2 of the License, or (at your
//     option) any later version.
//
//     This program is distributed in the hope that it will be useful, but
//     WITHOUT ANY WARRANTY; without even the implied warranty of
//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
//     Public License for more details.
//
//     You should have received a copy of the GNU General Public License along
//     with this program; if not, write to the Free Software Foundation, 
//     Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// </copyright>

namespace BetterAzureTableStorage.Tests
{
    using System;
    using System.Collections.Generic;
    using System.Data.Services.Client;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Net;
    using System.Reflection;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using Microsoft.WindowsAzure;

    /// <summary>
    /// This test class will test the BetterAzureTableStorage classes
    /// </summary>
    [TestClass]
    public class BetterAzureTableStorageTests
    {
        /// <summary>
        /// Gets or sets the credentials for accessing Azure Table Storage.
        /// </summary>
        /// <value>The credentials.</value>
        public static StorageCredentials Credentials { get; set; }

        /// <summary>
        /// Gets or sets the Azure Table Storage service root.
        /// </summary>
        /// <value>The service root.</value>
        public static Uri ServiceRoot { get; set; }

        /// <summary>
        /// A static string used for testing the expression translator
        /// </summary>
        private static string fStaticString = "fStaticString";

        /// <summary>
        /// Classes the initializer.
        /// </summary>
        /// <param name="context">The context.</param>
        [ClassInitialize]
        public static void ClassInitializer(TestContext context)
        {
            Credentials = CloudStorageAccount.DevelopmentStorageAccount.Credentials;
            ServiceRoot = new Uri(@"http://ipv4.fiddler:10002/devstoreaccount1");
            //ServiceRoot = CloudStorageAccount.DevelopmentStorageAccount.TableEndpoint;
        }

        /// <summary>
        /// Gets a new TTableStorageDataContext.
        /// </summary>
        /// <returns>A newly created TTableStorageDataContext</returns>
        /// <remarks>
        /// This will be called on each test method to setup a new context.
        /// </remarks>
        public TTableStorageDataContext GetNewContext()
        {
            return new TTableStorageDataContext(ServiceRoot, Credentials, (t =>
                {
                    TypeIdAttribute attr = t.GetCustomAttributes(typeof(TypeIdAttribute), false).FirstOrDefault() as TypeIdAttribute;
                    return new TTableStorageInfo()
                    {
                        ClassType = t,
                        TableName = t.BaseType.IsAbstract ? t.BaseType.Name : t.Name,
                        PropertyList = (from PropertyInfo prop in t.GetProperties()
                                        where prop.GetCustomAttributes(typeof(TTableTestIgnoreAttribute), false).FirstOrDefault() == null
                                        select new TTablePropertyInfo(prop, prop.Name)).ToList(),
                        ConditionalValue = attr != null ? (int?)attr.Discriminator : null
                    };
                }));
        }

        /// <summary>
        /// Initializer to be run before each test
        /// </summary>
        [TestInitialize]
        public void TestInit()
        {
            TTableStorageDataContext context = this.GetNewContext();
            context.CreateTableIfNotExists("TTestTableEntityAncestor");
            context.CreateTableIfNotExists("TTestTableEntityDot");
        }

        /// <summary>
        /// Test that exceptions are thrown on failed CRUD operations
        /// </summary>
        [TestMethod]
        public void CRUDFailure()
        {
            TTableStorageDataContext context = this.GetNewContext();

            TTestTableEntityBar bar = new TTestTableEntityBar()
            {
                BarProperty = 10
            };

            bool hasException = false;

            try
            {
                context.AddObject(bar);
                context.SaveChanges(System.Data.Services.Client.SaveChangesOptions.None);
                context.AddObject(bar);
                context.SaveChanges();
            }
            catch (TRetryException ex)
            {
                Assert.IsNotNull(ex.InnerException);
                Assert.AreEqual<Type>(typeof(WebException), ex.InnerException.GetType());
                WebException webEx = ex.InnerException as WebException;
                hasException = true;
            }

            Assert.IsTrue(hasException);
        }

        /// <summary>
        /// Test for continuation tokens (1000 result limit)
        /// </summary>
        /// <remarks>
        /// NOTE: There is no limit on Development Storage, this test is only meaningful
        /// when run on a Cloud Storage Account.
        /// </remarks>
        [TestMethod]
        public void QueryLimitTest()
        {
            TTableStorageDataContext context = this.GetNewContext();

            string partKey = Guid.NewGuid().ToString();

            for (int i = 0; i < 1500; i++)
            {
                TTestTableEntityBar bar = new TTestTableEntityBar()
                {
                    BarProperty = i,
                    BoolProperty = true,
                    PartitionKey = partKey,
                    RowKey = i.ToString()
                };

                context.AddObject(bar);
            }

            context.SaveChanges(SaveChangesOptions.Batch);

            var qry = context.CreateQuery<TTestTableEntityBar>().Where(b => b.PartitionKey == partKey);

            List<TTestTableEntityBar> list = qry.ToList();

            Assert.AreEqual<int>(1500, list.Count);
        }

        /// <summary>
        /// General test for CRUD operations on Azure Table Storage
        /// </summary>
        [TestMethod]
        public void AllCRUDTests()
        {
            TTableStorageDataContext context = this.GetNewContext();

            TTestTableEntityBar bar = new TTestTableEntityBar()
            {
                BarProperty = 10,
                BoolProperty = true
            };

            TTestTableEntityFoo foo = new TTestTableEntityFoo()
            {
                FooProperty = Guid.NewGuid(),
            };

            foo.PartitionKey = bar.PartitionKey;

            context.AddObject(foo);
            context.AddObject(bar);
            context.SaveChanges(System.Data.Services.Client.SaveChangesOptions.None);

            var qry = context.CreateQuery<TTestTableEntityBar>().Where(b => b.PartitionKey == bar.PartitionKey && b.RowKey == bar.RowKey);

            Assert.AreEqual<int>(bar.BarProperty, qry.ToList().FirstOrDefault().BarProperty);
            Assert.AreEqual<bool>(bar.BoolProperty, qry.ToList().FirstOrDefault().BoolProperty);

            Guid newFooGuid = Guid.NewGuid();
            foo.FooProperty = newFooGuid;

            context.UpdateObject(foo);

            context.SaveChanges();

            //var fooQry = context.CreateQuery<TTestTableEntityFoo>().Where(f => f.PartitionKey == foo.PartitionKey && f.RowKey == foo.RowKey);
            var fooQry = context.CreateQuery<TTestTableEntityFoo>().Where(f => f.FooProperty == foo.FooProperty);

            Assert.AreEqual<Guid>(foo.FooProperty, fooQry.ToList().FirstOrDefault().FooProperty);

            context.DeleteObject(foo);
            context.DeleteObject(bar);

            context.SaveChanges();

            var foobarQry = context.CreateQuery<TTestTableEntityAncestor>().Where(fb => fb.PartitionKey == foo.PartitionKey || fb.PartitionKey == bar.PartitionKey);

            Assert.AreEqual<int>(0, foobarQry.ToList().Count());
        }

        [TestMethod]
        public void NonInheritedEntityTypeAllCrudTests()
        {
            TTableStorageDataContext context =
            new TTableStorageDataContext(ServiceRoot, Credentials, (t =>
            {
                return new TTableStorageInfo()
                {
                    ClassType = t,
                    TableName = t.Name,
                    PropertyList = (from PropertyInfo prop in t.GetProperties()
                                    select new TTablePropertyInfo(prop, null)).ToList(),
                };
            }));

            Guid dot1TestGuid = Guid.NewGuid();
            Guid dot2TestGuid = Guid.NewGuid();
            TTestTableEntityDot dot1 = new TTestTableEntityDot(dot1TestGuid.ToString(), dot1TestGuid.ToString(), DateTime.Now);
            TTestTableEntityDot dot2 = new TTestTableEntityDot(dot2TestGuid.ToString(), dot2TestGuid.ToString(), DateTime.Now);


            dot1.PartitionKey = dot2.PartitionKey;

            context.AddObject(dot1);
            context.AddObject(dot2);
            context.SaveChanges();

            var qry = context.CreateQuery<TTestTableEntityDot>().Where(d1 => d1.RowKey == dot1.RowKey);


            ////Non enumerable ops are not supported yet
            ////int testSum = qry.Count();
            ////Assert.Fail();

            ////foreach (TTestTableEntityBar newBar in qry)
            ////{
            ////    int x = 10;
            ////}

            Assert.AreEqual<string>(dot1.RowKey, qry.ToList().FirstOrDefault().RowKey);

            context.UpdateObject(dot1);
            context.SaveChanges();

            var dot1Qry = context.CreateQuery<TTestTableEntityDot>().Where(d1 => dot1.PartitionKey == d1.PartitionKey && dot1.RowKey == d1.RowKey);

            Assert.AreEqual<string>(dot1.RowKey, dot1Qry.ToList().FirstOrDefault().RowKey);

            context.DeleteObject(dot1);
            context.DeleteObject(dot2);

            context.SaveChanges();

            var dot1dot2Qry = context.CreateQuery<TTestTableEntityDot>().Where(fb => fb.PartitionKey == dot1.PartitionKey || fb.PartitionKey == dot2.PartitionKey);

            Assert.AreEqual<int>(0, dot1dot2Qry.ToList().Count());
        }

        private Guid ID { get; set; }

        [TestMethod]
        public void QueryTranslatorExpandTest()
        {
            TTableStorageDataContext context = this.GetNewContext();

            context.CreateTableIfNotExists(typeof(TTestTableEntityBar).BaseType.Name);

            var qry = context.CreateQuery<TTestTableEntityBar>().Expand("Prop1, Prop2, Prop3,Top/Bottom").Expand("PropX");
            TTableStorageQueryTranslator translator = this.CreateTranslator(qry.Expression);
            Assert.AreEqual<string>("()", translator.TranslatedText);

            Assert.AreEqual<int>(5, translator.ExpansionPaths.Count);

            Assert.AreEqual<string>("PropX", translator.ExpansionPaths[0]);
            Assert.AreEqual<string>("Prop1", translator.ExpansionPaths[1]);
            Assert.AreEqual<string>("Prop2", translator.ExpansionPaths[2]);
            Assert.AreEqual<string>("Prop3", translator.ExpansionPaths[3]);
            Assert.AreEqual<string>("Top/Bottom", translator.ExpansionPaths[4]);
        }

        /// <summary>
        /// Test that the expression translator can handle various expression type without
        /// throwing an exception.
        /// </summary>
        [TestMethod]
        public void QueryTranslatorTest()
        {
            TTableStorageDataContext context = this.GetNewContext();

            string localString = "localString";

            context.CreateTableIfNotExists(typeof(TTestTableEntityBar).BaseType.Name);

            IQueryable<TTestTableEntityBar> qry;
            string result;

            this.ID = new Guid(1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4);
            qry = context.CreateQuery<TTestTableEntityBar>().Where(bar => bar.TestID == new Guid(1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4));
            result = this.Translate(qry.Expression);
            Assert.AreEqual<string>(String.Format(@"()?$filter=(TestID%20eq%20guid'{0}')", this.ID.ToString()), result);

            qry = context.CreateQuery<TTestTableEntityBar>().Where(bar => bar.PartitionKey == localString);
            result = this.Translate(qry.Expression);
            Assert.AreEqual<string>(@"()?$filter=(PartitionKey%20eq%20'localString')", result);
            (qry as TTableStorageQuery<TTestTableEntityBar>).RenameProperty = null;
            qry = context.CreateQuery<TTestTableEntityBar>().Where(bar => bar.PartitionKey == fStaticString);
            result = this.Translate(qry.Expression);
            Assert.AreEqual<string>(@"()?$filter=(PartitionKey%20eq%20'fStaticString')", result);

            qry = context.CreateQuery<TTestTableEntityBar>().Where(bar => localString == "TEST");
            result = this.Translate(qry.Expression);
            Assert.AreEqual<string>(@"()?$filter=('localString'%20eq%20'TEST')", result);

            qry = context.CreateQuery<TTestTableEntityBar>().Where(bar => bar.BarProperty < 5);
            result = this.Translate(qry.Expression);
            Assert.AreEqual<string>(@"()?$filter=(BarProperty%20lt%205)", result);

            qry = context.CreateQuery<TTestTableEntityBar>().Where(bar => bar.BarProperty > 5);
            result = this.Translate(qry.Expression);
            Assert.AreEqual<string>(@"()?$filter=(BarProperty%20gt%205)", result);

            qry = context.CreateQuery<TTestTableEntityBar>().Where(bar => bar.BarProperty <= 5);
            result = this.Translate(qry.Expression);
            Assert.AreEqual<string>(@"()?$filter=(BarProperty%20le%205)", result);

            qry = context.CreateQuery<TTestTableEntityBar>().Where(bar => bar.BarProperty >= 5);
            result = this.Translate(qry.Expression);
            Assert.AreEqual<string>(@"()?$filter=(BarProperty%20ge%205)", result);

            qry = context.CreateQuery<TTestTableEntityBar>().Where(bar => bar.BarProperty != 5);
            result = this.Translate(qry.Expression);
            Assert.AreEqual<string>(@"()?$filter=(BarProperty%20ne%205)", result);

            qry = context.CreateQuery<TTestTableEntityBar>().Where(bar => bar.BarProperty >= 5 && bar.BarProperty <= 10);
            result = this.Translate(qry.Expression);
            Assert.AreEqual<string>(@"()?$filter=((BarProperty%20ge%205)%20and%20(BarProperty%20le%2010))", result);

            qry = context.CreateQuery<TTestTableEntityBar>().Where(bar => bar.BarProperty >= 5 || bar.BarProperty <= 10);
            result = this.Translate(qry.Expression);
            Assert.AreEqual<string>(@"()?$filter=((BarProperty%20ge%205)%20or%20(BarProperty%20le%2010))", result);

            bool localFalse = false;
            qry = context.CreateQuery<TTestTableEntityBar>().Where(bar => localFalse != true);
            result = this.Translate(qry.Expression);
            Assert.AreEqual<string>(@"()?$filter=(false%20ne%20true)", result);

            bool localTrue = true;
            qry = context.CreateQuery<TTestTableEntityBar>().Where(bar => localTrue != false);
            result = this.Translate(qry.Expression);
            Assert.AreEqual<string>(@"()?$filter=(true%20ne%20false)", result);
        }

        /// <summary>
        /// Test that the expression translator throws an exception when an invalid method
        /// is found
        /// </summary>
        [TestMethod]
        ////[ExpectedException(typeof(NotSupportedException))]
        public void QueryTranslatorTestInvalidMethod()
        {
            TTableStorageDataContext context = this.GetNewContext();

            context.CreateTableIfNotExists(typeof(TTestTableEntityFoo).BaseType.Name);

            IQueryable qry = context.CreateQuery<TTestTableEntityFoo>().Where(foo => foo.PartitionKey == "TEST").Distinct();
            string result = this.Translate(qry.Expression);
        }

        [TestMethod]
        public void ContextTransactionTrackingTest()
        {
            TTableStorageDataContext context = this.GetNewContext();

            context.CreateTableIfNotExists(typeof(TTestTableEntityFoo).BaseType.Name);

            Guid guid = Guid.NewGuid();

            TTestTableEntityFoo foo = new TTestTableEntityFoo()
            {
                AncestorProperty = guid.ToString(),
                EnumProperty = TTestEnum.Value3,
                FooProperty = guid,
                PartitionKey = guid.ToString(),
                RowKey = guid.ToString(),
                Timestamp = DateTime.UtcNow
            };

            Assert.AreEqual<ulong>(0UL, context.TransactionCount);

            context.AddObject(foo);
            context.SaveChanges();

            Assert.AreEqual<ulong>(1UL, context.TransactionCount);

            TTableStorageDataContext_Accessor accessor = new TTableStorageDataContext_Accessor(new PrivateObject(context));
            TTableStorageQuery<TTestTableEntityFoo> qry = new TTableStorageQuery<TTestTableEntityFoo>(accessor.GetTableInfo(typeof(TTestTableEntityFoo)),
                tn => context.CreateEngine(tn),
                null,
                null);

            var actualFooQry = qry.Where(f => f.PartitionKey == guid.ToString() && f.RowKey == guid.ToString());

            Assert.AreEqual<ulong>(1UL, context.TransactionCount);

            TTestTableEntityFoo actualFoo = actualFooQry.ToList().FirstOrDefault();
            Assert.AreEqual<TTestEnum>(foo.EnumProperty, actualFoo.EnumProperty);
            Assert.AreEqual<string>(foo.FooProperty.ToString(), actualFoo.FooProperty.ToString());
            Assert.AreEqual<string>(foo.AncestorProperty, actualFoo.AncestorProperty);

            context.DeleteObject(foo);
            context.SaveChanges();

            Assert.AreEqual<ulong>(3UL, context.TransactionCount);
        }

        /// <summary>
        /// Test that entities are materialized properly when no rename query is provided.
        /// </summary>
        [TestMethod]
        public void QueryDefaultRenameFieldUsageTest()
        {
            TTableStorageDataContext context = this.GetNewContext();

            context.CreateTableIfNotExists(typeof(TTestTableEntityFoo).BaseType.Name);

            Guid guid = Guid.NewGuid();

            TTestTableEntityFoo foo = new TTestTableEntityFoo()
            {
                AncestorProperty = guid.ToString(),
                EnumProperty = TTestEnum.Value3,
                FooProperty = guid,
                PartitionKey = guid.ToString(),
                RowKey = guid.ToString(),
                Timestamp = DateTime.UtcNow
            };

            context.AddObject(foo);
            context.SaveChanges();

            TTableStorageDataContext_Accessor accessor = new TTableStorageDataContext_Accessor(new PrivateObject(context));
            TTableStorageQuery<TTestTableEntityFoo> qry = new TTableStorageQuery<TTestTableEntityFoo>(accessor.GetTableInfo(typeof(TTestTableEntityFoo)),
                tn => context.CreateEngine(tn),
                null,
                null);

            TTestTableEntityFoo actualFoo = qry.Where(f => f.PartitionKey == guid.ToString() && f.RowKey == guid.ToString()).ToList().FirstOrDefault();
            Assert.AreEqual<TTestEnum>(foo.EnumProperty, actualFoo.EnumProperty);
            Assert.AreEqual<string>(foo.FooProperty.ToString(), actualFoo.FooProperty.ToString());
            Assert.AreEqual<string>(foo.AncestorProperty, actualFoo.AncestorProperty);

            context.DeleteObject(foo);
            context.SaveChanges();
        }

        /// <summary>
        /// Test that ArgumentNullException is thrown when TTableStorageQueryProvider constructor
        /// is called with null provider
        /// </summary>
        [TestMethod]
        //[ExpectedException(typeof(ArgumentNullException))]
        public void TTableStorageQueryConstructorTest_Null1()
        {
            bool exceptionCaught = false;
            try
            {
                TTableStorageQuery<object> query = new TTableStorageQuery<object>(null, Expression.Constant("Test"));
            }
            catch (ArgumentNullException)
            {
                exceptionCaught = true;
            }

            Assert.IsTrue(exceptionCaught);
        }

        /// <summary>
        /// Test that ArgumentNullException is thrown when TTableStorageQueryProvider constructor
        /// is called with null expression
        /// </summary>
        //[TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void TTableStorageQueryConstructorTest_Null2()
        {
            bool exceptionCaught = false;
            try
            {
                TTableStorageQuery<object> query = new TTableStorageQuery<object>(new TTableStorageQueryProvider(new TTableStorageInfo("Test"), t => null, null), null);
            }
            catch (ArgumentNullException)
            {
                exceptionCaught = true;
            }

            Assert.IsTrue(exceptionCaught);
        }

        /// <summary>
        /// Test that ArgumentOutOfRangeException is thrown
        /// </summary>
        [TestMethod]
        //[ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void TTableStorageQueryConstructorTest_OutOfRange1()
        {
            bool exceptionCaught = false;
            try
            {
                TTableStorageQuery<object> provider = new TTableStorageQuery<object>(
                   new TTableStorageQueryProvider(new TTableStorageInfo("Test"), t => null, null),
                   Expression.Constant("Test"));
            }
            catch (ArgumentOutOfRangeException)
            {
                exceptionCaught = true;
            }
            Assert.IsTrue(exceptionCaught);
        }

        /// <summary>
        /// Translates the specified expression into an OData query
        /// </summary>
        /// <param name="expression">The expression to translate.</param>
        /// <returns>An OData query based on <paramref name="expression"/></returns>
        private string Translate(Expression expression)
        {
            TTableStorageQueryTranslator translator = new TTableStorageQueryTranslator();
            return translator.Translate(
                expression,
                t =>
                {
                    return t.Name;
                }, null);
        }

        private TTableStorageQueryTranslator CreateTranslator(Expression expression)
        {
            TTableStorageQueryTranslator translator = new TTableStorageQueryTranslator();
            translator.Translate(
                expression,
                t =>
                {
                    return t.Name;
                }, null);

            return translator;
        }

        [TestMethod]
        public void SingleEntityResultTest()
        {
            TTableStorageDataContext context = this.GetNewContext();

            context.CreateTableIfNotExists(typeof(TTestTableEntityFoo).BaseType.Name);

            Guid guid = Guid.NewGuid();

            TTestTableEntityFoo foo = new TTestTableEntityFoo()
            {
                AncestorProperty = guid.ToString(),
                EnumProperty = TTestEnum.Value3,
                FooProperty = guid,
                PartitionKey = guid.ToString(),
                RowKey = guid.ToString(),
                Timestamp = DateTime.UtcNow
            };

            TTestTableEntityFoo foo2 = new TTestTableEntityFoo()
            {
                AncestorProperty = guid.ToString(),
                EnumProperty = TTestEnum.Value3,
                FooProperty = Guid.NewGuid(),
                PartitionKey = guid.ToString(),
                RowKey = Guid.NewGuid().ToString(),
                Timestamp = DateTime.UtcNow
            };
            context.AddObject(foo);
            context.AddObject(foo2);
            context.SaveChanges(SaveChangesOptions.None);

            ////var qry = context.CreateQuery<TTestTableEntityFoo>().Where(f => f.FooProperty == guid);
            ////var actual = qry.Where(f => f.RowKey == guid.ToString()).FirstOrDefault();
            ////Assert.IsNotNull(actual);

            var qry = context.CreateQuery<TTestTableEntityFoo>();
            var actual = qry.Where(f => f.FooProperty == foo2.FooProperty);
            List<TTestTableEntityFoo> templist = actual.ToList();////.ToList().FirstOrDefault();

            TTestTableEntityFoo actualFoo = context.CreateQuery<TTestTableEntityFoo>().Where(f => f.PartitionKey == foo2.PartitionKey).FirstOrDefault();

            Assert.IsNotNull(actualFoo);

            context.DeleteObject(foo);
            context.DeleteObject(foo2);
            context.SaveChanges();
        }

        [TestMethod]
        public void DerivedQueryTest()
        {
            TTableStorageDataContext context = this.GetNewContext();

            context.CreateTableIfNotExists(typeof(TTestTableEntityFoo).BaseType.Name);

            Guid guid1 = Guid.NewGuid();
            Guid guid2 = Guid.NewGuid();

            TTestTableEntityFoo foo1 = new TTestTableEntityFoo()
            {
                AncestorProperty = guid1.ToString(),
                EnumProperty = TTestEnum.Value3,
                FooProperty = guid1,
                PartitionKey = guid1.ToString(),
                RowKey = guid1.ToString(),
                Timestamp = DateTime.UtcNow,
            };

            TTestTableEntityBar bar1 = new TTestTableEntityBar()
            {
                RowKey = guid2.ToString(),
                PartitionKey = guid1.ToString(),
            };

            context.AddObject(foo1);
            context.AddObject(bar1);
            context.SaveChanges();

            List<TTestTableEntityBar> list1 = context.CreateQuery<TTestTableEntityBar>().ToList();
            List<TTestTableEntityBar> list2 = context.CreateQuery<TTestTableEntityBar>().Where(x => x.BarProperty != 43).ToList();
            List<TTestTableEntityAncestor> list3 = context.CreateQuery<TTestTableEntityAncestor>().ToList();

            //// If it didn't blow up, we're good.
        }

        [TestMethod]
        public void ExpandTest()
        {
            TTableStorageDataContext context = this.GetNewContext();

            context.CreateTableIfNotExists(typeof(TTestTableEntityFoo).BaseType.Name);
            context.CreateTableIfNotExists(typeof(TTestTableEntityDot).Name);

            Guid guid = Guid.NewGuid();
            Guid guid2 = Guid.NewGuid();
            Guid guid3 = Guid.NewGuid();

            Guid dot3Link = Guid.NewGuid();

            TTestTableEntityFoo foo1 = new TTestTableEntityFoo()
            {
                AncestorProperty = guid.ToString(),
                EnumProperty = TTestEnum.Value3,
                FooProperty = guid,
                PartitionKey = guid.ToString(),
                RowKey = guid.ToString(),
                Timestamp = DateTime.UtcNow,
                TestID = dot3Link
            };
            TTestTableEntityFoo foo2 = new TTestTableEntityFoo()
            {
                AncestorProperty = guid2.ToString(),
                EnumProperty = TTestEnum.Value1,
                FooProperty = guid2,
                PartitionKey = guid.ToString(),
                RowKey = guid2.ToString(),
                Timestamp = DateTime.UtcNow,
            };
            TTestTableEntityFoo foo3 = new TTestTableEntityFoo()
            {
                AncestorProperty = guid3.ToString(),
                EnumProperty = TTestEnum.Value2,
                FooProperty = guid3,
                PartitionKey = guid.ToString(),
                RowKey = guid3.ToString(),
                Timestamp = DateTime.UtcNow,
            };

            TTestTableEntityDot dot1 = new TTestTableEntityDot()
            {
                PartitionKey = guid.ToString(),
                RowKey = Guid.NewGuid().ToString(),
                LinkRowKey = guid.ToString()
            };

            TTestTableEntityDot dot2 = new TTestTableEntityDot()
            {
                PartitionKey = guid.ToString(),
                RowKey = Guid.NewGuid().ToString(),
                LinkRowKey = guid.ToString()
            };

            TTestTableEntityDot dot3 = new TTestTableEntityDot()
            {
                PartitionKey = guid.ToString(),
                RowKey = Guid.NewGuid().ToString(),
                LinkRowKey = guid.ToString(),
                TestID = dot3Link
            };

            TTestTableEntityDot dot4 = new TTestTableEntityDot()
            {
                PartitionKey = guid.ToString(),
                RowKey = Guid.NewGuid().ToString(),
                LinkRowKey = guid2.ToString()
            };

            context.AddObject(foo1);
            context.AddObject(foo2);
            context.AddObject(foo3);
            context.AddObject(dot1);
            context.AddObject(dot2);
            context.AddObject(dot3);
            context.AddObject(dot4);
            context.SaveChanges(SaveChangesOptions.None);

            IQueryable<TTestTableEntityFoo> qry = context.CreateQuery<TTestTableEntityFoo>().Expand("Dots, One");
            qry = qry.Where<TTestTableEntityFoo>(f => f.PartitionKey == guid.ToString());
            List<TTestTableEntityBar> bars = qry.Select<TTestTableEntityFoo, TTestTableEntityBar>(
                f => new TTestTableEntityBar() { BarProperty = f.FooProperty.GetHashCode() }).ToList();

            Assert.AreEqual<int>(3, bars.Count);

            List<TTestTableEntityFoo> foos = context.CreateQuery<TTestTableEntityFoo>().Expand("Dots, One")
                .Where<TTestTableEntityFoo>(f => f.PartitionKey == guid.ToString()).ToList();

            Assert.AreEqual<int>(3, foos.Count);

            foos = context.CreateQuery<TTestTableEntityFoo>().Expand("Dots, One")
                .Where<TTestTableEntityFoo>(f => f.PartitionKey == guid.ToString() && f.RowKey == guid.ToString()).ToList();

            Assert.AreEqual<int>(1, foos.Count);
            Assert.AreEqual<int>(3, foos[0].Dots.Count);
            Assert.IsNotNull(foos[0].One);

            qry = context.CreateQuery<TTestTableEntityFoo>().Expand("Dots, One");
            qry = qry.Where<TTestTableEntityFoo>(f => f.PartitionKey == guid.ToString());
            List<TTestTableEntityDot> dots = qry.Select(f => f.One).ToList();

            Assert.AreEqual<int>(3, dots.Count);

            qry = context.CreateQuery<TTestTableEntityFoo>().Expand("Dots, One");
            qry = qry.Where<TTestTableEntityFoo>(f => f.PartitionKey == guid.ToString());
            List<TTestTableEntityDot> manyDots = qry.SelectMany(f => f.Dots).ToList();

            Assert.AreEqual<int>(4, manyDots.Count);
        }

        [TestMethod]
        public void CountTest()
        {
            TTableStorageDataContext context = this.GetNewContext();

            context.CreateTableIfNotExists(typeof(TTestTableEntityFoo).BaseType.Name);
            context.CreateTableIfNotExists(typeof(TTestTableEntityDot).Name);

            // this is failing, but it may be because of development storage.
            // we're seeing the same problem with deleting unused stations in WebOrder (unrelated project).
            // if they work on the live deployment we'll catch this below and assert the exception
            // until then it will be inclusive.
            try
            {
                context.CreateQuery<TTestTableEntityFoo>().Where(f => f.RowKey == "blah" && f.RowKey.ToLower() == "Fixed".ToLower() && f.AncestorProperty == "literal").FirstOrDefault();
            }
            catch
            {
                Assert.Inconclusive("wait to see if deleting unused stations on the live deployment works. if it does this is just a azure emulator problem and should be marked as passing.");
            }

        }
    }
}
